(*
  Copyright (c) 2009 Barry Schwartz

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
*)

open Dim
open FontForge
open GlyphMetric
open Graphic
open OpenType
open Substitute
open UniTools
open UTypes
open XNum

(* font metrics *)
type font_parameter = {
  hyphen_glyph : glyph_desc;
  skew_glyph : glyph_desc;
  margin_glyph : glyph_desc;
  space_glyph : glyph_desc;
  foreign_glyph : glyph_desc;
  slant : num;
  space : num;
  space_stretch : num;
  space_shrink : num;
  x_height : num;
  quad : num;
  extra_space : num;
  num_shift_1 : num;
  num_shift_2 : num;
  num_shift_3 : num;
  denom_shift_1 : num;
  denom_shift_2 : num;
  super_shift_1 : num;
  super_shift_2 : num;
  super_shift_3 : num;
  sub_shift_1 : num;
  sub_shift_2 : num;
  super_drop : num;
  sub_drop : num;
  delim_1 : num;
  delim_2 : num;
  axis_height : num;
  rule_thickness : num;
  big_op_spacing_1 : num;
  big_op_spacing_2 : num;
  big_op_spacing_3 : num;
  big_op_spacing_4 : num;
  big_op_spacing_5 : num
} (* with sexp_of *)

type font_type = | OpenTypeCFF | TrueType | TFM | Other (* with sexp_of *)

type font_metric = {
  id : string;                       (* Unique internal identifier. *)
  name : string;
  ps_name : string;
  file_name : UniText.t;
  font_type : font_type;
  first_glyph : int;
  last_glyph : int;
  design_size : num;
  at_size : num;
  check_sum : num;
  parameter : font_parameter;
  get_glyph : uc_char -> glyph_desc;
  get_unicode : glyph_desc -> uc_string;
  get_composer : 'box 'cmd . ('box, 'cmd) get_composer_type;
  kerning : font_metric -> int -> int -> lig_kern;
  draw_simple_glyph : font_metric -> int -> glyph_text -> simple_box;
  accent_base_point : font_metric -> glyph_metric -> (num * num);
  accent_attach_point : font_metric -> glyph_metric -> (num * num);
  get_glyph_bitmap : font_metric -> uc_char -> GlyphBitmap.glyph;
  get_glyph_name : int -> string;
  get_glyph_index : string -> int;
  code_to_glyph_index : int -> int;
  glyph_name_to_code : string -> int;
  glyph_metric : glyph_metric array;
  ff_font : FFfont.t option;
}

and ('box, 'cmd) get_composer_type =
    font_metric -> UniText.t -> FeatureSet.t -> (font_metric, 'box, 'cmd) glyph_composer

and simple_box =
  | Empty
  | SimpleGlyph of int * font_metric * glyph_text
  | Rule of num * num
  | Image of num * num * string
  | Group of ((num, simple_box) graphic_command) list
  | Command of simple_cmd

and simple_cmd =
    [
    | `DVI_Special of string
    | `PDF_Code of string
    | `PDF_Info of pdf_object           (* Should be a `PDF_Dict *)
    | `PDF_Catalog of pdf_object        (* Should be a `PDF_Dict *)
    | `PDF_Register of pdf_object * int
    ]

and pdf_object =
    [
    | `PDF_Null
    | `PDF_Name of UniTools.UniText.t
    | `PDF_String of UniTools.UniText.t
    | `PDF_Bool of bool
    | `PDF_Int of int
    | `PDF_Real of num
    | `PDF_Array of pdf_object list
    | `PDF_Dict of (UniTools.UniText.t * pdf_object) list
    | `PDF_Indirect of pdf_object
    | `PDF_Unencrypted of pdf_object
    | `PDF_Uncompressed of pdf_object
    | `PDF_ByteStream of pdf_object * string
    | `PDF_FileStream of pdf_object * UniTools.UniText.t
    | `PDF_ImageStream of UniTools.UniText.t
    | `PDF_Reference of int
    ]

(* with sexp_of *)

type glyph_spec =
  | GlyphIndex of int | GlyphChar of uc_char | GlyphName of string

type adjustment_spec = | AdjKern of num | AdjLig of glyph_spec

module GlyphSpecTrie : DynamicTrie.S with type elt = glyph_spec
  
(* User specified modifications of font parameters. *)
type font_load_params = {
  flp_size     : num;                (* scale font to this size     *)
  flp_encoding : uc_string array;    (* overrides built in encoding *)

  (* FIX: replace these two by a complete font_parameter *)
  flp_hyphen_glyph : glyph_desc;     (* specifies the hyphen glyph  *)
  flp_skew_glyph   : glyph_desc;     (* specifies the skew glyph    *)

  flp_letter_spacing : num;          (* additional letter spacing   *)
  flp_extra_pos   : adjustment_spec GlyphSpecTrie.t; (* additional kerning pairs and ligatures *)
  flp_extra_subst : adjustment_spec GlyphSpecTrie.t; (* additional kerning pairs and ligatures *)
  flp_extra_kern  : (glyph_spec * extra_kern_info) list (* kerning with border glyphs *)
}

(* pages *)
type page = {
  p_contents : simple_box;
  p_number   : int;
  p_width    : num;
  p_height   : num;
}

val default_bitmap_resolution : int ref
val default_mf_mode : string ref
val new_fontmetric_id : unit -> string
val get_glyph : font_metric -> uc_char -> glyph_desc
val get_unicode : font_metric -> glyph_desc -> uc_string
val index_to_glyph : font_metric -> int -> glyph_desc
val glyph_exists : font_metric -> int -> bool
val glyph_spec_to_index : (uc_char -> int) -> (string -> int) -> glyph_spec -> int
val get_glyph_metric : font_metric -> glyph_desc -> glyph_metric
val next_glyph : font_metric -> glyph_desc -> glyph_desc
val get_glyph_composer : ('box, 'cmd) get_composer_type
val get_lig_kern : font_metric -> glyph_desc -> glyph_desc -> lig_kern
val draw_simple_glyph : font_metric -> int -> glyph_text -> simple_box
val draw_displaced_simple_glyph : num -> num -> font_metric -> int -> glyph_text -> simple_box
val draw_glyph : font_metric -> glyph_desc -> glyph_text -> simple_box
val get_hyphen_glyph : font_metric -> glyph_desc
val get_skew_glyph : font_metric -> glyph_desc
val accent_base_point : font_metric -> glyph_metric -> (num * num)
val accent_attach_point : font_metric -> glyph_metric -> (num * num)
val accent_base_point_x_height : font_metric -> glyph_metric -> (num * num)
val accent_attach_point_top : font_metric -> glyph_metric -> (num * num)
val accent_position : font_metric -> glyph_metric -> font_metric -> glyph_metric -> (num * num)
val construct_accent : font_metric -> glyph_desc -> font_metric -> glyph_desc -> glyph_metric
  
(* Shorthand to access the dimension of a normal and an extended space of the font. *)
val space_glue : font_metric -> dim
val xspace_glue : font_metric -> dim

val empty_font : font_metric
val empty_parameter : font_parameter
val empty_load_params : font_load_params

val get_opened_ff_font : UniText.t -> FFfont.t
val quit_using_ff_font : UniText.t -> unit
